home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / UDP.C < prev    next >
C/C++ Source or Header  |  1997-09-06  |  7KB  |  309 lines

  1. /* Internet User Data Protocol (UDP)
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "netuser.h"
  7. #include "iface.h"
  8. #include "udp.h"
  9. #include "icmp.h"
  10.  
  11. #if !defined(_lint)
  12. static char rcsid[] OPTIONAL = "$Id: udp.c,v 1.15 1997/09/07 00:31:16 root Exp root $";
  13. #endif
  14.  
  15. static struct udp_cb *lookup_udp (struct socket *thesocket);
  16.  
  17. struct mib_entry Udp_mib[] = {
  18.     { "",            { 0 } },
  19.     { "udpInDatagrams",    { 0 } },
  20.     { "udpNoPorts",        { 0 } },
  21.     { "udpInErrors",    { 0 } },
  22.     { "udpOutDatagrams",    { 0 } },
  23. };
  24.  
  25.  
  26. /* UDP control structures list */
  27. struct udp_cb *Udps;
  28.  
  29. /* Create a UDP control block for lsocket, so that we can queue
  30.  * incoming datagrams.
  31.  */
  32. struct udp_cb *
  33. open_udp (lsocket, r_upcall)
  34. struct socket *lsocket;
  35. void (*r_upcall)(struct iface *,struct udp_cb *,int16);
  36. {
  37. register struct udp_cb *up;
  38.  
  39.     if ((up = lookup_udp (lsocket)) != NULLUDP)    {
  40.         /* Already exists */
  41.         Net_error = CON_EXISTS;
  42.         return NULLUDP;
  43.     }
  44.     up = (struct udp_cb *)callocw (1, sizeof (struct udp_cb));
  45.     up->socket.address = lsocket->address;
  46.     up->socket.port = lsocket->port;
  47.     up->r_upcall = r_upcall;
  48.  
  49.     up->next = Udps;
  50.     Udps = up;
  51.     return up;
  52. }
  53.  
  54.  
  55.  
  56. /* Send a UDP datagram */
  57. int
  58. send_udp (lsocket, fsocket, tos, ttl, data, length, id, df)
  59. struct socket *lsocket;        /* Source socket */
  60. struct socket *fsocket;        /* Destination socket */
  61. char tos;            /* Type-of-service for IP */
  62. char ttl;            /* Time-to-live for IP */
  63. struct mbuf *data;        /* Data field, if any */
  64. int16 length;            /* Length of data field */
  65. int16 id;            /* Optional ID field for IP */
  66. char df;            /* Don't Fragment flag for IP */
  67. {
  68. struct mbuf *bp;
  69. struct pseudo_header ph;
  70. struct udp udp;
  71. uint32 laddr;
  72.  
  73.     if (length != 0 && data != NULLBUF)
  74.         trim_mbuf (&data, length);
  75.     else
  76.         length = len_p (data);
  77.  
  78.     length += UDPHDR;
  79.  
  80.     laddr = lsocket->address;
  81.     if (laddr == INADDR_ANY)
  82.         laddr = locaddr (fsocket->address);
  83.  
  84.     udp.source = lsocket->port;
  85.     udp.dest = fsocket->port;
  86.     udp.length = length;
  87.  
  88.     /* Create IP pseudo-header, compute checksum and send it */
  89.     ph.length = length;
  90.     ph.source = laddr;
  91.     ph.dest = fsocket->address;
  92.     ph.protocol = UDP_PTCL;
  93.  
  94.     if ((bp = htonudp (&udp, data, &ph)) == NULLBUF)    {
  95.         Net_error = NO_MEM;
  96.         free_p (data);
  97.         return 0;
  98.     }
  99.     udpOutDatagrams++;
  100.     (void) ip_send (laddr, fsocket->address, UDP_PTCL, tos, ttl, bp, length, id, df);
  101.     return (int)length;
  102. }
  103.  
  104.  
  105. /* Accept a waiting datagram, if available. Returns length of datagram */
  106. int
  107. recv_udp (up, fsocket, bp)
  108. register struct udp_cb *up;
  109. struct socket *fsocket;        /* Place to stash incoming socket */
  110. struct mbuf **bp;        /* Place to stash data packet */
  111. {
  112. struct socket sp;
  113. struct mbuf *buf;
  114. int16 length;
  115.  
  116.     if (up == NULLUDP)    {
  117.         Net_error = NO_CONN;
  118.         return -1;
  119.     }
  120.     if (up->rcvcnt == 0)    {
  121.         Net_error = WOULDBLK;
  122.         return -1;
  123.     }
  124.     buf = dequeue (&up->rcvq);
  125.     up->rcvcnt--;
  126.  
  127.     /* Strip socket header */
  128.     (void) pullup (&buf, (unsigned char *)&sp, sizeof(struct socket));
  129.  
  130.     /* Fill in the user's foreign socket structure, if given */
  131.     if (fsocket != NULLSOCK)    {
  132.         fsocket->address = sp.address;
  133.         fsocket->port = sp.port;
  134.     }
  135.     /* Hand data to user */
  136.     length = len_p (buf);
  137.     if (bp != NULLBUFP)
  138.         *bp = buf;
  139.     else
  140.         free_p (buf);
  141.     return (int)length;
  142. }
  143.  
  144.  
  145. /* Delete a UDP control block */
  146. int
  147. del_udp (conn)
  148. struct udp_cb *conn;
  149. {
  150. struct mbuf *bp;
  151. register struct udp_cb *up;
  152. struct udp_cb *udplast = NULLUDP;
  153.  
  154.     for (up = Udps; up != NULLUDP; udplast = up, up = up->next)    {
  155.         if (up == conn)
  156.             break;
  157.     }
  158.     if (up == NULLUDP)    {
  159.         /* Either conn was NULL or not found on list */
  160.         Net_error = INVALID;
  161.         return -1;
  162.     }
  163.     /* Get rid of any pending packets */
  164.     while (up->rcvcnt != 0)    {
  165.         bp = up->rcvq;
  166.         up->rcvq = up->rcvq->anext;
  167.         free_p (bp);
  168.         up->rcvcnt--;
  169.     }
  170.     /* Remove from list */
  171.     if (udplast != NULLUDP)
  172.         udplast->next = up->next;
  173.     else
  174.         Udps = up->next;    /* was first on list */
  175.  
  176.     free ((char *)up);
  177.     return 0;
  178. }
  179.  
  180.  
  181. /* Process an incoming UDP datagram */
  182. void
  183. udp_input (iface, ip, bp, rxbroadcast)
  184. struct iface *iface;    /* Input interface */
  185. struct ip *ip;        /* IP header */
  186. struct mbuf *bp;    /* UDP header and data */
  187. int rxbroadcast;    /* The only protocol that accepts 'em */
  188. {
  189. struct pseudo_header ph;
  190. struct udp udp;
  191. struct udp_cb *up;
  192. struct socket lsocket;
  193. struct socket fsocket;
  194. struct mbuf *packet;
  195. int16 length;
  196.  
  197.     if (bp == NULLBUF)
  198.         return;
  199.  
  200.     /* Create pseudo-header and verify checksum */
  201.     ph.source = ip->source;
  202.     ph.dest = ip->dest;
  203.     ph.protocol = ip->protocol;
  204.     length = ip->length - IPLEN - ip->optlen;
  205.     ph.length = length;
  206.  
  207.     /* Peek at header checksum before we extract the header. This
  208.      * allows us to bypass cksum() if the checksum field was not
  209.      * set by the sender.
  210.      */
  211.     udp.checksum = udpcksum (bp);
  212.     if (udp.checksum != 0 && cksum (&ph, bp, length) != 0)    {
  213.         /* Checksum non-zero, and wrong */
  214.         udpInErrors++;
  215.         free_p (bp);
  216.         return;
  217.     }
  218.     /* Extract UDP header in host order */
  219.     if (ntohudp (&udp, &bp) != 0)    {
  220.         /* Truncated header */
  221.         udpInErrors++;
  222.         free_p (bp);
  223.         return;
  224.     }
  225.     /* If this was a broadcast packet, pretend it was sent to us */
  226.     if (rxbroadcast)
  227.         lsocket.address = iface->addr;
  228.     else
  229.         lsocket.address = ip->dest;
  230.  
  231.     lsocket.port = udp.dest;
  232.     /* See if there's somebody around to read it */
  233.     if ((up = lookup_udp (&lsocket)) == NULLUDP
  234. #ifdef UDPACCESS
  235.        || tcp_check (UDPaccess, ip->source, udp.dest) > 0
  236. #endif
  237.        )    {
  238.         /* Nope, return an ICMP message */
  239.         if (!rxbroadcast)    {
  240.             bp = htonudp (&udp, bp, &ph);
  241.             (void) icmp_output (ip, bp, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, NULL);
  242.         }
  243.         udpNoPorts++;
  244.         free_p (bp);
  245.         return;
  246.     }
  247.     /* Create space for the foreign socket info */
  248.     if ((packet = pushdown (bp, sizeof(fsocket))) == NULLBUF)    {
  249.         /* No space, drop whole packet */
  250.         free_p (bp);
  251.         udpInErrors++;
  252.         return;
  253.     }
  254.     fsocket.address = ip->source;
  255.     fsocket.port = udp.source;
  256.     memcpy (&packet->data[0], (char *)&fsocket, sizeof(fsocket));
  257.  
  258.     /* Queue it */
  259.     enqueue (&up->rcvq,packet);
  260.     up->rcvcnt++;
  261.     udpInDatagrams++;
  262.     if (up->r_upcall)
  263.         (*up->r_upcall) (iface, up, (int16) up->rcvcnt);
  264. }
  265.  
  266.  
  267. /* Look up UDP socket. 
  268.  * Return control block pointer or NULLUDP if nonexistant
  269.  * As side effect, move control block to top of list to speed future
  270.  * searches.
  271.  */
  272. static struct udp_cb *
  273. lookup_udp (thesocket)
  274. struct socket *thesocket;
  275. {
  276. register struct udp_cb *up;
  277. struct udp_cb *uplast = NULLUDP;
  278.  
  279.     for (up = Udps; up != NULLUDP; uplast = up, up = up->next)    {
  280.         if (thesocket->port == up->socket.port && (thesocket->address == up->socket.address || up->socket.address == INADDR_ANY))    {
  281.             if (uplast != NULLUDP)    {
  282.                 /* Move to top of list */
  283.                 uplast->next = up->next;
  284.                 up->next = Udps;
  285.                 Udps = up;
  286.             }
  287.             return up;
  288.         }
  289.     }
  290.     return NULLUDP;
  291. }
  292.  
  293.  
  294.  
  295. #ifdef MSDOS
  296.  
  297. /* Attempt to reclaim unused space in UDP receive queues */
  298. void
  299. udp_garbage (red)
  300. int red;
  301. {
  302. register struct udp_cb *udp;
  303.  
  304.     for (udp = Udps; udp != NULLUDP; udp = udp->next)
  305.         mbuf_crunch (&udp->rcvq);
  306. }
  307.  
  308. #endif
  309.